#include <iostream>
#include <QtGui>
#include <stdexcept>
#include "SDL.h"
#include "SDL_image.h"
#include "SDL_ttf.h"
#include "../item.h"
#include "../itemfactory.h"
#include "../mapitem.h"
#include "../mapitemfactory.h"
#include "../location.h"
#include "../sdlevent.h"
#include "createmap.h"
#include "drawmap.h"
#include "../tree.h"
#include <string>

CreateMap::CreateMap(QWidget *parent) : QDialog(parent)
{
        // Initialize all variables
	mode_ = 0;
	loc_ = new Location();
	mapTree = new Tree(); 

	// Start the map window
	startMapWindow();

	information = new QLabel(tr("Write blueprint id, click the appropriate button.\nThen click in the gameworld where you want to place it."));

	itemEdit = new QLineEdit;
	mapItemEdit = new QLineEdit;
	locationName = new QLineEdit;
	mapName = new QLineEdit;
	
	placeItem = new QPushButton(tr("Place &Item:"));
	placeMapItem = new QPushButton(tr("Place &MapItem:"));
	createNewLocation = new QPushButton(tr("New Location"));
	saveLocationToMap = new QPushButton(tr("Save Location"));
	saveMapToDisk = new QPushButton(tr("Save Entire Map"));

	// Connect all the events to approprite slots
	connect(placeItem, SIGNAL(clicked()), this, SLOT(placeItemOnMap()));
	connect(placeMapItem, SIGNAL(clicked()), this, SLOT(placeMapItemOnMap()));
	connect(itemEdit, SIGNAL(textChanged(const QString &)), this, SLOT(setItem(const QString &)));
	connect(mapItemEdit, SIGNAL(textChanged(const QString &)), this, SLOT(setMapItem(const QString &)));
	connect(createNewLocation, SIGNAL(clicked()), this, SLOT(newLocation()));
	connect(saveLocationToMap, SIGNAL(clicked()), this, SLOT(addLocationToMap()));
	connect(saveMapToDisk, SIGNAL(clicked()), this, SLOT(saveMap()));
	connect(locationName, SIGNAL(textChanged(const QString &)), this, SLOT(setLocName(const QString &)));
	connect(mapName, SIGNAL(textChanged(const QString &)), this, SLOT(setMapName(const QString &)));
	
	// Layout of the window
	QVBoxLayout *buttonLayout = new QVBoxLayout;
	buttonLayout->addWidget(saveLocationToMap);
	buttonLayout->addWidget(placeItem);
	buttonLayout->addWidget(placeMapItem);
	buttonLayout->addWidget(saveMapToDisk);
	QVBoxLayout *inputLayout = new QVBoxLayout;
	inputLayout->addWidget(locationName);
	inputLayout->addWidget(itemEdit);
	inputLayout->addWidget(mapItemEdit);
	inputLayout->addWidget(mapName);
	QHBoxLayout *buttonInput = new QHBoxLayout;
	buttonInput->addLayout(buttonLayout);
	buttonInput->addLayout(inputLayout);
	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->addWidget(createNewLocation);
	mainLayout->addWidget(information);
	mainLayout->addLayout(buttonInput);
	setLayout(mainLayout);
	
	setWindowTitle(tr("Create/Edit Map"));
	setFixedHeight(sizeHint().height());
}

CreateMap::~CreateMap()
{
	delete loc_;
	delete drawMap_;
	delete mapTree;
}

// Make change the appropriate change on received X,Y coordinates
void CreateMap::makeChange(int x, int y)
{
        // 1 = item
	// 2 = mapItem
	if(mode_ == 1)
	{
		placeItemOnMap(x, y);
	}
	else if(mode_ == 2)
	{
		placeMapItemOnMap(x, y);
	}
	
}

// Used as slots to change mode when a button is pressed
void CreateMap::placeItemOnMap(){
	mode_ = 1;
	drawMap_->run(this);
}

void CreateMap::placeMapItemOnMap(){
	mode_ = 2;
	drawMap_->run(this);
}

// Create an item object from blueprint and place it on the map
void CreateMap::placeItemOnMap(int x, int y){
	
	ItemFactory *factory = new ItemFactory();
	
	try
	{
		Item* newItem = new Item();
		newItem = factory->build(inputItem);
		newItem->setX(x);
		newItem->setY(y);
		loc_->addItem(newItem);
		newItem = 0;
		
	}
	catch(itemfactory_error &texterror)
	{
		errorMessage("Error while loading Item");
	}
	
	delete factory;
}

// Create an mapitem object from blueprint and place it on the map
void CreateMap::placeMapItemOnMap(int x, int y){
	MapItemFactory *factory = new MapItemFactory();
	MapItem *garbage;
	
	try
	{
		garbage = loc_->map_[x][y];
		loc_->map_[x][y] = 0;
		loc_->map_[x][y] = factory->build(inputMapItem);
		delete garbage;
	}
	catch(mapitemfactory_error &texterror)
	{
		// Put the old mapitem back in case of error
		loc_->map_[x][y] = garbage;
		errorMessage("Error while loading MapItem");
	}
	
	delete factory;	
}

// Save user input to Item
void CreateMap::setItem(const QString & changedId)
{
	inputItem = changedId.toStdString();
}

// Save user input to MapItem
void CreateMap::setMapItem(const QString & changedId)
{
	inputMapItem = changedId.toStdString();
}

// Save user input to location name
void CreateMap::setLocName(const QString & locationNameInput)
{
	locName_ = locationNameInput.toStdString();
}
	
// Save user input to map name
void CreateMap::setMapName(const QString & mapNameInput)
{
	mapName_ = mapNameInput.toStdString();
}

// Add current location to map
void CreateMap::addLocationToMap()
{
	// Add the location to the map tree
	if(mapTree->find_l(locName_))
	{
		if(overwrite("There already exists a location with this name on the map.\n "
			      "Do you want to overwrite?"))
		{
			// Remove the location with the same name from the map
			mapTree->remove(locName_);
	
			loc_->setName(locName_);
			loc_->right_node = 0;
			loc_->left_node = 0;
			mapTree->add(loc_);
			
			// We have to create a new location to avoid trouble with pointers
			// when changing, deleting location in the map
			loc_ = 0;
			loc_ = new Location();
			drawMap_->setLocation(loc_);
		}
	}
	else
	{
		loc_->setName(locName_);
		loc_->right_node = 0;
		loc_->left_node = 0;
		mapTree->add(loc_);

		// We have to create a new location to avoid trouble with pointers
		// when changing, deleting location in the map
		loc_ = 0;
		loc_ = new Location();
		drawMap_->setLocation(loc_);
		
	}
}

// Crate a new location
void CreateMap::newLocation()
{
	Location *garbage;
	garbage = loc_;
	loc_ = 0;
	delete garbage;
	loc_ = new Location();
	drawMap_->setLocation(loc_);
}

void CreateMap::saveMap()
{
	mapTree->save(mapName_);
}		

// Show warning message
void CreateMap::errorMessage(std::string errorText)
{
	QMessageBox::warning(this, tr("ERROR"),
			     tr(errorText.c_str()),
			     QMessageBox::Ok | QMessageBox::Default);
}

// Overwrite warning message
bool CreateMap::overwrite(std::string errorText)
{
	int r = QMessageBox::warning(this, tr("Map"),
				     tr(errorText.c_str()),
				     QMessageBox::Yes | QMessageBox::Default,
				     QMessageBox::No);
	if (r == QMessageBox::Yes) {
		return true;
	} 
	else if (r == QMessageBox::No) {
		return false;
	}
}

void CreateMap::startMapWindow()
{
	 // Initialize the SDL window

	screen = NULL;
	//Initiera SDL med ljud och video-stöd
	if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) < 0)
	{
		std::cout << "Throw exception for SDL_Init";
	}
	
	// Försök att sätta rätt videoläge
	screen = SDL_SetVideoMode(1024, 768, 32, SDL_HWSURFACE|SDL_DOUBLEBUF);
	if(screen == NULL)
	{
		std::cout << "Throw exception for SDL_SetVideoMode";
	}
	
	// Initiera font-stöd
	if(TTF_Init() < 0)
	{
		std::cout << "Throw exception for TTF_Init";
	}
	
	SDL_WM_SetCaption("Adventure 2 Editor v0.2 ALPHA", NULL);
	
	// Draw the map
	drawMap_ = new DrawMap(screen, loc_);

}
